import { parentPort, workerData } from "worker_threads";
import path from "path";
import { DataHandler, StrategyBacktest } from "../../trader";
import { getDistanceScore } from "../../trader/util";
import { appendFileSync } from "fs";
import { KLineDTO } from "../kline-history/KLineHistory.entity";

export interface Message {
  type: string;
  [x: string]: any;
}

let history: KLineDTO[] = [];
let symbol = ''
if (parentPort) {
  history = workerData.history;
  // 在主进程或主线程中
  parentPort.on("message", msg => {
    const result = fitnessStrategy(msg, workerData.symbol);
    parentPort.postMessage(result);
  });
} else {
  // 在 fork 或 worker 中
  process.on("message", msg => {
    if (msg.type && msg.type === 'workerData') {
      history = msg.workerData.history;
      symbol = msg.workerData.symbol;
      return;
    }
    const result = fitnessStrategy(msg, symbol);
    // 将结果发送给主线程
    process.send(result);
  });
}

export function fitnessStrategy(genes, symbol?: string) {
  //         exceptional_undulation_rate_15m + exceptional_undulation_rate_4h + exceptional_undulation_rate_1d > ${genes[12]} &&
  //         volume_rate_15m + volume_rate_4h + volume_rate_1d > ${genes[2]} &&
  //     close_ma_rate_15m + close_ma_rate_4h + close_ma_rate_1d > ${genes[5]} &&
  //         close_ma_rate_15m + close_ma_rate_4h + close_ma_rate_1d < ${genes[13]} &&
  try {
    const code = `
    function strategy (kline: MergeData, indicators: Indicators, mixIndicator: CustomIndicators) {
      // const ma120_15m = indicators.get('ma120');
      const { 
        close_ma_rate_15m,
        close_ma_rate_4h,
        exceptional_undulation_rate_4h,
        volume_rate_15m,
        volume_rate_4h,
        point_peaks_15m,
        point_valleys_15m,
        slope_15m,
      } = mixIndicator;
      const positive = kline.close > kline.open;
      const buy_close_ma_target = ${genes[0]};
      const sell_close_ma_target = ${genes[1]};
      const buy_volume_rate_15m = ${genes[2]};
      const sell_volume_rate_15m = ${genes[3]};
      const buy_exceptional_undulation_4h_target = ${genes[4]};
      const sell_exceptional_undulation_4h_target =${genes[5]};
      if (
        close_ma_rate_15m > sell_close_ma_target &&
        point_peaks_15m >= 2 &&
        volume_rate_4h > 0.1 &&
        (slope_15m === 1 || slope_15m === 3) &&
        volume_rate_15m > sell_close_ma_target &&
        close_ma_rate_4h > sell_close_ma_target * 2 &&
        exceptional_undulation_rate_4h > sell_exceptional_undulation_4h_target &&
        positive
      ) {
        return "SELL";
      } else if (
        close_ma_rate_15m < buy_close_ma_target &&
        point_valleys_15m >= 2 &&
        volume_rate_4h > 0.1 &&
        (slope_15m === -1 || slope_15m === -3) &&
        volume_rate_15m > buy_volume_rate_15m &&
        close_ma_rate_4h < buy_close_ma_target * 2 &&
        exceptional_undulation_rate_4h > buy_exceptional_undulation_4h_target &&
        !positive
      ) {
        return "BUY";
      }
    }
    var config = {
      mode: 1
    };
    `
    // console.log(code)
    const { profitRate, maxDrawdownRate, ...others } = train(history, {
      code
    });
    
    if (maxDrawdownRate > -0.3 && profitRate > 0.2) {
      const resultFilePath = path.resolve(__dirname, './result_strategy.json');
      appendFileSync(resultFilePath, JSON.stringify({
        result: { maxDrawdownRate, profitRate, ...others },
        code: code.replace(/\n|\s{2,}/g, '')
      }))
    }
    let score = 0;
    if (maxDrawdownRate === 0) {
      score = 0;
    } else {
      score = getDistanceScore(Math.abs(maxDrawdownRate * 100)) / 3;
    }
    if (others.buyCount > 0 && others.sellCount > 0) {
      score + 20;
    }
    if (profitRate > 0) {
      score += profitRate * 100 * 2;
    }
    console.log(`profitRate： ${profitRate}`,  `maxDrawdownRate: ${maxDrawdownRate} score:${score}`)
    // score += getScore(others.buyCount, 12)
    return score;
  } catch (error) {
    console.log(error);
    return 0;
  }
}


export function train(history: KLineDTO[], options?: {
  code?: string
}) {
  const symbol = history[0].symbol
  const dataHander = new DataHandler('mock');
  const strategyBacktest = new StrategyBacktest({symbol, ...options});
  strategyBacktest.init(symbol);
  dataHander.on('interval:15m', (data) => {
    strategyBacktest.addData(data, '15m')
  });

  dataHander.on('interval:4h', (data) => {
    strategyBacktest.addData(data, '4h')
  });

  dataHander.on('interval:1d', (data) => {
    strategyBacktest.addData(data, '1d')
  });

  dataHander.on('update:4h', (data) => {
    strategyBacktest.updateData(data, '4h');
  });
  dataHander.on('update:1d', (data) => {
    strategyBacktest.updateData(data, '1d');
  });

  for (let i = 0; i < history.length; i++) {
    const element = history[i];
    dataHander.handleHistory({
      timestamp: new Date(element.time).getTime(),
      ...element,
    })
  }
  const result = strategyBacktest.getResult(symbol);
  // console.log(result)
  strategyBacktest.destroyed();
  return result
}
